package eerbaar.internal.memory;

import eerbaar.memory.IMemory;
import eerbaar.shared.tree.DefaultPayload;
import eerbaar.shared.tree.INode;
import eerbaar.shared.tree.IPayload;
import eerbaar.shared.tree.NodeCmdFactory;
import eerbaar.shared.tree.NodeFactory;
import eerbaar.shared.tree.policy.PolicyFactory;

public class Memory implements IMemory {

    private static final String COMMANDS = "commands";
    private static final String IDEA = "idea";
    private static final String IDEA_PRIORITY = "idea-priority";
    private static final String IDEA_PATTERN = "idea-pattern";
    private static final String INTERNAL = "internal";
    private static final String THINGS = "things";
    private static final String TIME = "time";
    private static final String VOCABULARY = "vocabulary";
    private INode commandsNode = NodeFactory.create(Memory.COMMANDS);
    private INode ideaNode = NodeFactory.create(Memory.IDEA);
    private INode ideaPriorityNode = NodeFactory.create(Memory.IDEA_PRIORITY);
    private INode ideaPatternNode = NodeFactory.create(Memory.IDEA_PATTERN);
    private INode internalNode = NodeFactory.create(Memory.INTERNAL);
    private INode root = NodeFactory.createRoot();
    private INode thingsNode = NodeFactory.create(Memory.THINGS);
    private INode timeNode = NodeFactory.create(Memory.TIME);
    private INode vocabularyNode = NodeFactory.create(Memory.VOCABULARY);

    public Memory() {
        init();
    }

    public Memory(INode node) {
        this.root = node;
        init();
    }

    @Override
    public void addEvent(String event) {

        addEvent(null, event);
    }

    @Override
    public void addEvent(String eventClass, String event) {

        IPayload payload = new DefaultPayload(event);
        INode node = NodeFactory.create(payload);
        if (eventClass != null) {
            node.getAttributes().set(String.class, "class", eventClass);
        }

        this.timeNode.add(node);
    }

    @Override
    public INode getCommandsNode() {
        return this.commandsNode;
    }

    @Override
    public INode getIdeaNode() {

        this.ideaNode = getNode(this.root, this.ideaNode);
        this.ideaNode.addListener(PolicyFactory.getUniquePolicy());

        return this.ideaNode;
    }

    @Override
    public INode getIdeaPatternNode() {

        this.ideaPatternNode = getNode(this.root, this.ideaPatternNode);
        this.ideaPatternNode.addListener(PolicyFactory.getUniquePolicy());

        return this.ideaPatternNode;
    }

    @Override
    public INode getIdeaPriorityNode() {

        this.ideaPriorityNode = getNode(this.root, this.ideaPriorityNode);
        this.ideaPriorityNode.addListener(PolicyFactory.getUniquePolicy());

        return this.ideaPriorityNode;
    }

    @Override
    public INode getInternalNode() {

        this.internalNode = getNode(this.root, this.internalNode);
        this.internalNode.addListener(PolicyFactory.getUniquePolicy());

        return this.internalNode;
    }

    private INode getNode(INode parentNode, INode defaultNode) {

        INode test = NodeCmdFactory.findChild(parentNode, defaultNode
                .getPayload().getKey());
        if (test == null) {
            test = defaultNode;
            parentNode.add(defaultNode);
        }

        return test;
    }

    @Override
    public INode getRoot() {
        return this.root;
    }

    @Override
    public INode getThingsNode() {
        return this.thingsNode;
    }

    @Override
    public INode getTimeNode() {

        this.timeNode = getNode(this.root, this.timeNode);
        this.timeNode.addListener(PolicyFactory.getSizePolicy());
        this.timeNode.addListener(PolicyFactory.getMergePolicy());
        return this.timeNode;
    }

    @Override
    public INode getVocabularyNode() {

        this.vocabularyNode = getNode(this.root, this.vocabularyNode);
        this.commandsNode = getNode(this.vocabularyNode, this.commandsNode);
        this.thingsNode = getNode(this.vocabularyNode, this.thingsNode);
        getNode(this.thingsNode, NodeFactory.create("bone"));
        getNode(this.thingsNode, NodeFactory.create("tree"));
        this.vocabularyNode.addListener(PolicyFactory.getUniquePolicy());
        return this.vocabularyNode;
    }

    private void init() {
        getTimeNode();
        getIdeaNode();
        getIdeaPriorityNode();
        getIdeaPatternNode();
        getInternalNode();
        getVocabularyNode();
    }

    @Override
    public void setRoot(INode node) {
        this.root = node;
    }

    @Override
    public String toString() {
        return this.root.toString();
    }

}
